#! /usr/bin/python
# -*- coding: utf8 -*-

########################################################
# Part of MILIM NIRDAFOT project.
# Written by H. Magal, 2014
# See details on the project at the site:
#   https://sites.google.com/site/nirdafotdownloads/home
########################################################

import wx
import subprocess
import codecs
import hmHebrew

__version__ = '1.01'

NikudChars =    (hmHebrew.SHEVA, hmHebrew.HATAF_SEGOL, hmHebrew.HATAF_PATAH, hmHebrew.HATAF_QAMATS,
                 hmHebrew.HIRIQ, hmHebrew.TSERE, hmHebrew.SEGOL, hmHebrew.PATAH, hmHebrew.QAMATS,
                 hmHebrew.HOLAM, hmHebrew.HOLAM_HASER_FOR_VAV,
                 hmHebrew.QUBUTS, hmHebrew.DAGESH_OR_MAPIQ, hmHebrew.SHIN_DOT, hmHebrew.SIN_DOT)

NikudButns =    (hmHebrew.SAMEKH+hmHebrew.SHEVA, hmHebrew.SAMEKH+hmHebrew.HATAF_SEGOL,
                 hmHebrew.SAMEKH+hmHebrew.HATAF_PATAH, hmHebrew.SAMEKH+hmHebrew.HATAF_QAMATS,
                 hmHebrew.SAMEKH+hmHebrew.HIRIQ, hmHebrew.SAMEKH+hmHebrew.TSERE,
                 hmHebrew.SAMEKH+hmHebrew.SEGOL, hmHebrew.SAMEKH+hmHebrew.PATAH,
                 hmHebrew.SAMEKH+hmHebrew.QAMATS, hmHebrew.VAV+hmHebrew.HOLAM,
                 hmHebrew.SAMEKH+hmHebrew.HOLAM_HASER_FOR_VAV,
                 hmHebrew.SAMEKH+hmHebrew.QUBUTS, hmHebrew.SAMEKH+hmHebrew.DAGESH_OR_MAPIQ,
                 hmHebrew.SHIN+hmHebrew.SHIN_DOT, hmHebrew.SHIN+hmHebrew.SIN_DOT)

arrowButtonsLabels = ('Delete', '|<<', '<', '>', '>>|', 'CopyText', 'Clip')

hebrew_chars = (hmHebrew.ALEF, hmHebrew.BET, hmHebrew.GIMEL, hmHebrew.DALET, hmHebrew.HE,
                hmHebrew.VAV, hmHebrew.ZAYIN, hmHebrew.HET, hmHebrew.TET, hmHebrew.YOD,
                hmHebrew.FINAL_KAF, hmHebrew.KAF, hmHebrew.LAMED, hmHebrew.FINAL_MEM,
                hmHebrew.MEM, hmHebrew.FINAL_NUN, hmHebrew.NUN, hmHebrew.SAMEKH, hmHebrew.AYIN,
                hmHebrew.FINAL_PE, hmHebrew.PE, hmHebrew.FINAL_TSADI, hmHebrew.TSADI, hmHebrew.QOF,
                hmHebrew.RESH, hmHebrew.SHIN, hmHebrew.TAV)

# main help frame class
class MyHelpFrame (wx.Frame):
    """ make a frame, inherits wx.Frame """
    def __init__ (self):
        ds = wx.DisplaySize()   # get screen dimensions
        height = ds [1]
        width = ds [0]
        frame_width = (width*4) / 5
        frame_height = (height*4) / 5
        # create a frame, no parent, default to wxID_ANY. The frame cannot be resized/maximized
        # the frame is generated to be positioned at the screen regarding the screen properties
        wx.Frame.__init__ (self, None, wx.ID_ANY, 'Nikuda Help', pos=(width/10, height/10), size=(frame_width, frame_height),
                           style=(wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN))

        panel = wx.Panel (self)
        sizer = wx.BoxSizer (wx.VERTICAL)

        helpfile = codecs.open ('nikuda.help.txt', 'r', 'utf-8')
        lines = helpfile.readlines ()                          # read all lines into a list of lines
        helpfile.close ()
        jline = ''.join (lines)                                 # join all lines into one string
        text = wx.TextCtrl (panel, style=wx.SIMPLE_BORDER | wx.VSCROLL | wx.TE_READONLY | wx.TE_MULTILINE | wx.TE_WORDWRAP,
                            size=((frame_width*99)/100, (frame_height*6)/7))
        text.AppendText (jline)
        text.SetInsertionPoint (0)
        text.Refresh ()
        sizer.Add (text, flag=wx.ALL | wx.EXPAND, border=4)

        panel.SetSizer (sizer)
        panel.Layout ()
        self.Show (True)                                        # show the frame


MENU_FILE_EXIT    = wx.NewId()
MENU_HELP_DLG     = wx.NewId()
MENU_ABOUT_DLG    = wx.NewId()

# main frame class
class MyFrame (wx.Frame):
    """ make a frame, inherits wx.Frame """
    def __init__ (self):
        self.N = len (NikudChars)
        ds = wx.DisplaySize()   # get screen dimensions
        height = ds [1]
        width = ds [0]
        frame_width = (width*4)/5
        frame_height = height / 2
        # create a frame, no parent, default to wxID_ANY. The frame cannot be resized/maximized
        # the frame is generated to be positioned at the screen regarding the screen properties
        wx.Frame.__init__ (self, None, wx.ID_ANY, 'Hebrew Nirdafot', pos=(width/10, height/10), size=(frame_width, frame_height),
          style=(wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN))

        panel = wx.Panel (self)
        vbox = wx.GridSizer (2, 1, 0, 0)    # 2 rows, 1 columns, vert_gap=0
        tbox = wx.GridSizer (2, 1, 0, 0)    # 2 rows, 1 columns, vert_gap=0

        #################################
        # Create the upper text control #
        #################################
        self.textent = wx.TextCtrl (panel, value='הכנס טקסט חדש פה')
        tbox.Add (self.textent, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=0)
        fnt = self.textent.GetFont ()                       # get font of text control
        fnt.SetPointSize (48)
        self.textent.SetFont (fnt)                          # set its font to final size
        self.textent.Refresh ()


        #################################
        # Create the lower text control #
        #################################
        # The TE_MULTILINE is needed since only TE_MULTILINE enables character styling (color, font etc.)
        self.textbox = wx.TextCtrl (panel, value='עברית קשה שפה', style=wx.TE_MULTILINE | wx.TE_READONLY)
        tbox.Add (self.textbox, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=0)
        fnt = self.textbox.GetFont ()                       # get font of text control
        fnt.SetPointSize (48)
        self.textbox.SetFont (fnt)                          # set its font to final size
        self.normal_color = wx.TextAttr (wx.Colour (0, 0, 0))
        self.green_color  = wx.TextAttr (wx.Colour (0, 255, 0))
        self.setTextStyle (0)
        self.textbox.SetInsertionPoint (1)
        self.textbox.Refresh ()
        vbox.Add (tbox, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP|wx.BOTTOM, border=height/100)

        bbox = wx.GridSizer (2, 1, 5, 0)            # 2 rows, 1 columns, vert_gap=5
        ##################################
        # Create the upper arrow buttons #
        ##################################
        hbox2 = wx.GridSizer (1, len (arrowButtonsLabels), 0, 10)     # 1 row, N columns, hor_gap=10
        for i in xrange (0, len (arrowButtonsLabels)):
            button = wx.Button (panel, id=wx.NewId (), label=arrowButtonsLabels [i], style=wx.BORDER_RAISED)
            fnt = button.GetFont ()                       # get font of text control
            fnt.SetPointSize (24)
            button.SetFont (fnt)                          # set its font to final size
            button.Refresh ()
            hbox2.Add (button, flag=wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER, border=8)
            button.Bind (wx.EVT_BUTTON, self.onControlButton)
        bbox.Add (hbox2, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP|wx.BOTTOM, border=height/100)


        ##################################
        # Create the lower NIKUD buttons #
        ##################################
        hbox1 = wx.GridSizer (1, self.N, 0, 10)     # 1 row, N columns, hor_gap=10
        for i in xrange (0, self.N):
            button = wx.Button (panel, id=wx.NewId (), label=NikudButns [i], style=wx.BORDER_RAISED)
            fnt = button.GetFont ()                       # get font of text control
            fnt.SetPointSize (48)
            button.SetFont (fnt)                          # set its font to final size
            button.Refresh ()
            hbox1.Add (button, flag=wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER, border=8)
            button.Bind (wx.EVT_BUTTON, self.onNikudButton)
        bbox.Add (hbox1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP|wx.BOTTOM, border=height/100)
        vbox.Add (bbox, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP|wx.BOTTOM, border=height/100)

        ######################
        # Create the menubar #
        ######################
        menuBar = wx.MenuBar ()             # Menu Bar. Create a MenuBar
        menu1 = wx.Menu ()                  # Build a Menu Object to go into the Menu Bar
        menu1.Append (MENU_FILE_EXIT, 'Exit')
        menuBar.Append (menu1, 'Exit')      # Place the Menu Item in the Menu Bar
        menu2 = wx.Menu ()                  # Build a Menu Object to go into the Menu Bar
        menu2.Append (MENU_HELP_DLG, 'Help')
        menu2.Append (MENU_ABOUT_DLG, 'About this program')
        menuBar.Append (menu2, 'Help')      # Place the Menu Item in the Menu Bar
        self.SetMenuBar (menuBar)           # Place the Menu Bar on the app

        panel.SetSizer (vbox)
        panel.Layout ()
        self.Show (True)                     # show the frame

        wx.EVT_MENU (self, MENU_FILE_EXIT,          self.CloseWindow)  # Define Events for the Menu Items
        wx.EVT_MENU (self, MENU_HELP_DLG,           self.showHelp)
        wx.EVT_MENU (self, MENU_ABOUT_DLG,          self.aboutDialogBox)


    # All NIKUD buttons comes here. Identify the button pressed, and insert that NIKUD int the text
    def onNikudButton (self, event):
        label = event.GetEventObject().GetLabel()
        for i in xrange (0, self.N):
            if label == NikudButns [i]:
                self.clearTextStyle ()                                  # remove the green color from prev char
                self.textbox.WriteText (NikudChars[i])
                self.setTextRangeStyle (self.textbox.GetInsertionPoint () - 1)
                break


    # Clear style for whole text
    def clearTextStyle (self):
         self.textbox.SetStyle (0, self.textbox.GetLastPosition (), self.normal_color)     # remove the green color from prev char


    # set style for char at location
    def setTextStyle (self, location):
         self.textbox.SetStyle (location, location+1, self.green_color)       # set the green color to new char
         self.last_location = location


    # set style for chars at range [last_location, current_location]
    def setTextRangeStyle (self, location):
         self.textbox.SetStyle (self.last_location, location+1, self.green_color) # set the green color to new char


    # All Control buttons comes here. Identify the button pressed, and act accordingly
    def onControlButton (self, event):
        label = event.GetEventObject().GetLabel()
        if label == 'CopyText':
            self.textbox.SetValue (self.textent.GetValue ())                # copy text from upper row to lower row
            self.setTextStyle (0)
            self.textbox.SetInsertionPoint (1)
            return
        if label == 'Delete':
            self.clearTextStyle ()
            ip = self.textbox.GetInsertionPoint ()
            self.textbox.Remove (ip-1, ip)
            self.textbox.SetInsertionPoint (ip-1)
            return
        if label == '|<<':
            self.clearTextStyle ()                                          # remove the green color from prev char
            i = self.textbox.GetLastPosition ()
            self.setTextStyle (i-1)
            self.textbox.SetInsertionPoint (i)
            return
        if label == '<':
            val = self.textbox.GetValue ()                                  # get string content
            for i in xrange (self.textbox.GetInsertionPoint (), self.textbox.GetLastPosition ()): # search forwards
                if val[i] in hebrew_chars:
                    self.clearTextStyle ()                                  # remove the green color from prev char
                    self.setTextStyle (i)
                    self.textbox.SetInsertionPoint (i+1)
                    break
            return
        if label == '>':
            val = self.textbox.GetValue ()                                  # get string content
            for i in xrange (self.textbox.GetInsertionPoint ()-2, -1, -1):             # search backwards
                if val[i] in hebrew_chars:
                    self.clearTextStyle ()                                  # remove the green color from prev char
                    self.setTextStyle (i)
                    self.textbox.SetInsertionPoint (i+1)
                    break
            return
        if label == '>>|':
            self.clearTextStyle ()                                          # remove the green color from prev char
            self.setTextStyle (0)
            self.textbox.SetInsertionPoint (1)
            return
        if label == 'Clip':
            arg1 = self.textbox.GetValue ()
            subprocess.call ('echo \"' + arg1 + '\" | xclip -in', shell=True)
            return

    def CloseWindow (self, event):
        self.Destroy ()


    def showHelp (self, event):
        lwindow = MyHelpFrame ()                                            # call this class


    def aboutDialogBox (self, event):
        s = 'This program was written by Hanoch Magal\n\n'
        s += 'More details can be found at the site\n"https://sites.google.com/site/nirdafotdownloads/home".\n\n'
        s += 'Program version: ' + __version__ + '\n'
        wx.MessageBox (s, 'About this program', wx.OK)


###### Main code ######
def main():
    app = wx.App ()
    MyFrame ()                          # call class MyFrame
    app.MainLoop ()                     # start the event loop


if __name__ == '__main__':
    main ()